#include "nerthread.h"



#include <QFile>
#include <QIODevice>
#include <QCryptographicHash>
#include <QByteArray>
#include <QDebug>
#include <QDir>

#include <QFileInfo>
#include <QVector>
#include <QPixmap>
#include <QImage>

#include "ner/bertinfer.h"
#include "pubdef.h"

#define CHECK_CANCEL if(checkCanceled())return;
static int nerId = 1;

// 将 std::map<std::string, std::vector<std::string>> 转换为 QMap<QString, QStringList>
QMap<QString, QStringList> ConvertStdMapToQtMap(const std::map<std::string, std::vector<std::string>>& stdMap) {
    QMap<QString, QStringList> qtMap;
    for (const auto& pair : stdMap) {
        QStringList stringList;
        for (const auto& str : pair.second) {
            stringList << QString::fromStdString(str);
        }
        qtMap.insert(QString::fromStdString(pair.first), stringList);
    }
    return qtMap;
}
NERThread::NERThread()
{
    m_nerId = nerId++;
    setTerminationEnabled(true);
//#ifdef QT_DEBUG
//    printf("create NERThread: %d\n", m_nerId);
//#endif
}


NERThread::~NERThread()
{
#ifdef QT_DEBUG
    printf("delete NERThread: %d\n", m_nerId);
#endif
}
void NERThread::run()
{
#ifdef QT_DEBUG
    printf("begin run NERThread: %d\n", m_nerId);
#endif
    bertText();
#ifdef QT_DEBUG
    printf("end run NERThread: %d\n", m_nerId);
#endif
    if(!m_isCancel)
    {
        emit returnNerResult(0);
    }
}

QMap<QString, QStringList> &NERThread::nerResult()
{
    return m_nerResult;
}

void NERThread::setInputText(std::string text)
{
    m_input = text;

}
bool nerLock = false;
void NERThread::setCancel()
{
    m_isCancel = true;
}


bool NERThread::checkCanceled()
{
    if(m_isCancel || !m_isRunning)
    {
#ifdef QT_DEBUG
        //        printf("OCRThread Canceled: %d\n", m_nerId);
#endif
        nerLock = false;
        m_isRunning = false;
        return true;
    }
    return false;
}
QString NERThread::loadCacheIfPossible()
{
    QString key;

        QString loadFilePath;


        qint64 size = m_input.size();
        QByteArray byteInput(m_input.data(), static_cast<int>(size));
        QByteArray ba = QCryptographicHash::hash(byteInput, QCryptographicHash::Md5);

        key = QString("%1+%2+%3").arg(NER_VERSION).arg(size).arg(QString(ba.toHex()));

        loadFilePath = _settings->value(key, "").toString();

        if(QFile::exists(loadFilePath))
        {
            QFile inFile(loadFilePath);
            if (inFile.open(QIODevice::ReadOnly)) {
                printf("load Cache:%s,%s\n",qUtf8Printable(key), qUtf8Printable(loadFilePath));
                QDataStream inStream(&inFile);
                inStream >> m_nerResult;
                inFile.close();

                m_isRunning = false;
                nerLock = false;
                return key;
            }
        }
        else
        {
            _settings->remove(key);
        }

    return key;
}

void NERThread::nerTask()
{
    BertInfer *infer = BertInfer::getInstance();
    std::map<std::string, std::vector<std::string>> temp = infer->runInference(m_input);
    m_nerResult = ConvertStdMapToQtMap(temp);
}


void NERThread::saveNerCache(QString &key)
{
    //#ifdef QT_DEBUG
    if(!key.isEmpty())
    {
        QString filePath = randomSaveFile();

        QFile saveFile(filePath);
        if (saveFile.open(QIODevice::WriteOnly)) {
            QDataStream out(&saveFile);
            out << m_nerResult ;

            saveFile.close();
            _settings->setValue(key, filePath);
            printf("save Cache:%s,%s\n",qUtf8Printable(key), qUtf8Printable(filePath));
        }
    }
    //#endif
}


void NERThread::bertText()
{
    while (nerLock) {
        msleep(200);
        if(m_isCancel)
        {
#ifdef QT_DEBUG
            printf("OCRThread Canceled: %d\n", m_nerId);
#endif
            return;
        }
    }
    nerLock = true;
    m_isRunning = true;

    //load cache
    QString key;
    key = loadCacheIfPossible();
    CHECK_CANCEL
            ;
    //ner
    nerTask();
    //saveFile
    saveNerCache(key);
    m_isRunning = false;
    nerLock = false;
}


